(function($) {

/* TreeView class */
TreeView = function(treeId) {
	this.element = null;
	this.childs = [];
	this.parent = null;
	this.curSel = null;
	this.onSelectChange = function(item) {};

	this.attach(treeId);
}

TreeView.prototype = {

	attach: function(element) {
		this.element = $(element);
		if (this.element.size()!=1) return;

		var parent = this;
		this.element.children('li').each(function() {
			var child = new TreeItem();
			parent.childs.push(child);
			child.parent = parent;
			child.attach(this);
		});
		this._decorate();
	},
	
	collapseAll: function() {
		TreeView.recursiveCollapse(this);
	},
	
	expandAll: function() {
		TreeView.recursiveExpand(this);
	},
	
	getSelect: function() {
		return this.curSel;
	},
	
	addChild: function(item) {
		this.childs.push(item);
		item.parent = this;
		this.element.append(item.element);
		this._decorate();
	},
	
	removeChild: function(item) {
		item.element.remove();
		var childs = $.grep(this.childs, function(value) {
			return value != item;
		});
		this.childs = childs;
		this._decorate();
	},

	select: function() {
		if (this.childs.length>0) this.childs[0].select();
	},
	
	_decorate: function() {
		this.element.addClass('treeview');
		var childElements = this.element.children('li');
		childElements.removeClass('first last')
		childElements.last().addClass('last');
		if (childElements.size() > 1) childElements.first().addClass('first');
	},
	
	_onItemClick: function(node) {
		if (this.curSel) this.curSel.element.removeClass('selected');
		this.curSel = node;
		this.curSel.element.addClass('selected');
		this.onSelectChange(this.curSel);
	}
}

TreeView.recursiveExpand = function(node) {
	$(node.childs).each(function (index, item) {
		item.expand();
		TreeView.recursiveExpand(item);
	});
}

TreeView.recursiveCollapse = function(node) {
	$(node.childs).each(function (index, item) {
		item.collapse();
		TreeView.recursiveCollapse(item);
	});
}

/* TreeItem class */
TreeItem = function() {
	this.childs = [];
	this.element = null;
	this.parent = null;
	this._onItemClick = function () {};
}

TreeItem.prototype = {

	attach: function(element) {
		this.element = $(element);
		if (this.element.size()!=1) return;

		var parent = this;
		this.element.children('ul').children('li').each(function() {
			var child = new TreeItem();
			parent.childs.push(child);
			child.parent = parent;
			child.attach(this);
		});
		
		this._decorate();
	},
	
	collapse: function() {
		if (!this.hasChild()) return;
		this.element.removeClass('open').addClass('closed');
		this.element.children('ul').hide();
	},
	
	expand: function() {
		if (!this.hasChild()) return;
		this.element.removeClass('closed').addClass('open');
		this.element.children('ul').show();
	},
	
	toggle: function() {
		if (this._isExpand()) this.collapse(); else this.expand();
	},
	
	hasChild: function() {
		return this.childs.length > 0;
	},

	addChild: function(item) {
		this.childs.push(item);
		item.parent = this;
		if (!this.element.is(':has(>ul)'))
			this.element.append('<ul></ul');
		this.element.children('ul').append(item.element);
		this._decorate();
	},
	
	remove: function() {
		this.parent.removeChild(this);
		this.parent.select();
	},
	
	removeChild: function(item) {
		item.element.remove();
		var childs = $.grep(this.childs, function(value) {
			return value != item;
		});
		this.childs = childs;
		if (!this.hasChild()) {
			this.element.children('ul').remove();
			this.element.children('.icon').remove();
		}
		this._decorate();
	},

	select: function() {
		this.element.children('.label').click();
	},
	
	_decorate: function() {
		var node = this;
		this._onItemClick = function (node) {
			this.parent._onItemClick(node);
		};
		
		this.element.children('span')
			.addClass('label')
			.click(function() {
				node.parent._onItemClick(node);
			});

		if (!this.hasChild()) return;
		if (!this.element.is(':has(>.icon)'))
			this.element.prepend(TreeItem.createIconElement(this));
			
		var childElements = this.element.children('ul').children('li');
		childElements.removeClass('first last')
		childElements.last().addClass('last');
		if (childElements.size() > 1) childElements.first().addClass('first');
		if (this.element.children('ul').is(':visible'))
			this.expand();
		else
			this.collapse();
	},
	
	_isExpand: function() {
		return $(this.element).children('ul').is(':visible');
	}
	
}

TreeItem.createIconElement = function(node) {
	var icon = $('<div class="icon">&nbsp;</div>');
	$(icon).click(function () { node.toggle(); });
	return icon;
}

TreeItem.createItem = function(data) {
	var item = new TreeItem();
	item.attach($('<li><span>'+data.name+'</span></li>'));
	return item;
}

})(jQuery)